package test.crypto;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import test.LocalProperties;

public class CryptoUtils {

    public  String AES;
    public  String KEY_FILE;
    public  String PROPERTIES_FILE;

    public CryptoUtils(String myAES) {
	this.AES = myAES;
    }

    /**
     * encrypt a value and generate a keyfile if the keyfile is not found then a
     * new one is created
     * 
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public String encrypt(String value, File keyFile)
    throws GeneralSecurityException, IOException {
	if (!keyFile.exists()) {
	    KeyGenerator keyGen = KeyGenerator.getInstance(AES);
	    keyGen.init(128);
	    SecretKey sk = keyGen.generateKey();
	    FileWriter fw = new FileWriter(keyFile);
	    fw.write(byteArrayToHexString(sk.getEncoded()));
	    fw.flush();
	    fw.close();
	}

	SecretKeySpec sks = getSecretKeySpec(keyFile);
	Cipher cipher = Cipher.getInstance(AES);
	cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
	byte[] encrypted = cipher.doFinal(value.getBytes());
	return byteArrayToHexString(encrypted);
    }

    public void myGenerator(String myPROPERTIES_FILE, String myKEY_FILE) {
	BufferedReader input = new BufferedReader(new InputStreamReader(
		System.in));
	try {
	    System.out.println("\nEnter Password:");
	    String clearPwd = input.readLine();

	    try {
		LocalProperties myProperty = new LocalProperties(
			myPROPERTIES_FILE);
		String encryptedPwd = encrypt(clearPwd, new File(myKEY_FILE));
		myProperty.setProperty("password", encryptedPwd);
		System.out.println("Password:"
			+ myProperty.getProperty("password"));
	    } catch (GeneralSecurityException e) {
		e.printStackTrace();
	    }
	} catch (IOException e) {
	    System.exit(1);
	}
    }

    public String GetCleanPassword(String myPROPERTIES_FILE, String myKEY_FILE) {

	LocalProperties myProperty = new LocalProperties(myPROPERTIES_FILE);
	String encryptedPwd = myProperty.getProperty("password");
	String cleanPassword = null;
	try {
	    cleanPassword = decrypt(encryptedPwd, new File(myKEY_FILE));
	} catch (GeneralSecurityException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}
	return cleanPassword;
    }

    /**
     * decrypt a value
     * 
     * @throws GeneralSecurityException
     * @throws IOException
     */
    public  String decrypt(String message, File keyFile)
    throws GeneralSecurityException, IOException {
	SecretKeySpec sks = getSecretKeySpec(keyFile);
	System.out.println(AES);
	Cipher cipher = Cipher.getInstance(AES);
	cipher.init(Cipher.DECRYPT_MODE, sks);
	byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
	return new String(decrypted);
    }

    private  SecretKeySpec getSecretKeySpec(File keyFile)
    throws NoSuchAlgorithmException, IOException {
	byte[] key = readKeyFile(keyFile);
	SecretKeySpec sks = new SecretKeySpec(key, AES);
	return sks;
    }

    private static byte[] readKeyFile(File keyFile)
    throws FileNotFoundException {
	Scanner scanner = new Scanner(keyFile).useDelimiter("\\Z");
	String keyValue = scanner.next();
	scanner.close();
	return hexStringToByteArray(keyValue);
    }

    private static String byteArrayToHexString(byte[] b) {
	StringBuffer sb = new StringBuffer(b.length * 2);
	for (int i = 0; i < b.length; i++) {
	    int v = b[i] & 0xff;
	    if (v < 16) {
		sb.append('0');
	    }
	    sb.append(Integer.toHexString(v));
	}
	return sb.toString().toUpperCase();
    }

    private static byte[] hexStringToByteArray(String s) {
	byte[] b = new byte[s.length() / 2];
	for (int i = 0; i < b.length; i++) {
	    int index = i * 2;
	    int v = Integer.parseInt(s.substring(index, index + 2), 16);
	    b[i] = (byte) v;
	}
	return b;
    }


}